package com.tianji.remark.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.dto.remark.LikedTimesDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.constants.RedisConstants;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.pojo.dto.LikeRecordFormDTO;
import com.tianji.remark.pojo.po.LikedRecord;
import com.tianji.remark.service.ILikedRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static com.tianji.common.constants.MqConstants.Exchange.LIKE_RECORD_EXCHANGE;
import static com.tianji.common.constants.MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 */
@Service
@RequiredArgsConstructor
public class LikedRecordServiceRedisImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {

    private final RabbitMqHelper mqHelper;
    private final StringRedisTemplate redisTemplate;

    @Override
    public void addLikeRecord(LikeRecordFormDTO recordDTO) {
        // 点赞或取消点赞
        Boolean success = recordDTO.getLiked() ? like(recordDTO) : unLike(recordDTO);

        // 点赞失败直接返回
        if (!success) {
            return;
        }

        // 执行成功需要更新点赞数量
        Long size = redisTemplate.opsForSet().size(RedisConstants.LIKES_BIZ_KEY_PREFIX + recordDTO.getBizId());
        if (size == null) {
            return;
        }

        // 更新总的点赞数到缓存
        redisTemplate.opsForZSet().add(RedisConstants.LIKES_TIMES_KEY_PREFIX + recordDTO.getBizType(),
                recordDTO.getBizId().toString()
                , size);

    }

    @Override
    public Set<Long> isBizLiked(List<Long> bizIds) {
        Long userId = UserContext.getUser();
        // 查询点赞状态
        List<Object> objects = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            StringRedisConnection redisConnection = (StringRedisConnection) connection;
            for (Long bizId : bizIds) {
                String key = RedisConstants.LIKES_BIZ_KEY_PREFIX + bizId;
                redisConnection.sIsMember(key, userId.toString());
            }
            return null;
        });

        // 返回点赞状态
        return IntStream.range(0, objects.size()) // 创建从0到集合size的流
                .filter(i -> (boolean) objects.get(i))  // 遍历每个元素，保留结果为true的角标i
                .mapToObj(bizIds::get)  // 用角标i取bizIds中的对应数据，就是点赞过的id
                .collect(Collectors.toSet());
    }

    private Boolean unLike(LikeRecordFormDTO recordDTO) {
        String key = RedisConstants.LIKES_BIZ_KEY_PREFIX + recordDTO.getBizId();

        // 使用sortedSET数据结构删除缓存中的数据
        Long result = redisTemplate.opsForSet().remove(key, UserContext.getUser().toString());

        // set删除后返回改变的key，一般正常删除返回1
        return result != null && result > 0;
    }

    private Boolean like(LikeRecordFormDTO recordDTO) {
        String key = RedisConstants.LIKES_BIZ_KEY_PREFIX + recordDTO.getBizId();

        // 点赞则新增缓存点赞状态
        Long result = redisTemplate.opsForSet().add(key, UserContext.getUser().toString());
        return result != null && result > 0;
    }

    @Override
    public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {
        // 读取并移除Redis中缓存的点赞总数
        String key = RedisConstants.LIKES_TIMES_KEY_PREFIX + bizType;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(key, maxBizSize);

        while (CollUtils.isNotEmpty(typedTuples)) {

            List<LikedTimesDTO> list = new ArrayList<>(typedTuples.size());
            for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
                String bizId = tuple.getValue();
                Double likeCounts = tuple.getScore();
                if (bizId == null || likeCounts == null) {
                    continue;
                }
                list.add(new LikedTimesDTO(Long.valueOf(bizId), likeCounts.intValue()));
            }

            // 发送MQ消息
            mqHelper.send(LIKE_RECORD_EXCHANGE, StringUtils.format(LIKED_TIMES_KEY_TEMPLATE, bizType), list);

            redisTemplate.opsForZSet().popMin(key, maxBizSize);

            // 持久化点赞数据
            /*// 1.更新本地数据库
            List<Long> bizIds = list.stream().map(LikedTimesDTO::getBizId).collect(Collectors.toList());
            // 1.1.查询旧数据
            List<LikedRecord> oldRecord = lambdaQuery().in(LikedRecord::getBizId, bizIds).list();
            Map<Long, LikedRecord> oldStatMap = new HashMap<>(0);
            if(CollUtils.isNotEmpty(oldRecord)) {
                oldStatMap = oldRecord.stream().collect(Collectors.toMap(LikedRecord::getBizId, Function.identity()));
            }
            // 1.2.处理为PO
            List<LikedRecord> listPo = new ArrayList<>(list.size());
            for (LikedTimesDTO dto : list) {
                // 判断bizId是否已经存在
                LikedRecord stat = oldStatMap.get(dto.getBizId());
                if(stat == null){
                    // 不存在，新增
                    stat = new LikedRecord();
                    stat.setBizId(dto.getBizId());
                    stat.(dto.getLikedTimes());
                    stat.setBizType(bizType);
                }else{
                    // 已经存在，需要更新
                    stat.setLikedTimes(dto.getLikedTimes());
                }
                listPo.add(stat);
            }
            // 1.3.批处理
            saveOrUpdateBatch(listPo);*/
        }

    }
}